﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

// NotReviewedButNeeded
#pragma once
#include "NdbObjectCopyUtils.h"
#include "NdbTypeTraits.h"
#include "NdbCloneBehavior.h"
#include "TransferOwnership.h"

//////////////////////////////////////////////////////////////////////////
// 根据类型使用不同的copy。对NdbObject使用NdbObjectCopyUtils::CopyObject，对非NdbObject，调用拷贝构造函数。
namespace gcmp
{
    template<class I, class Enable = void>
    class NdbCopyHelper
    {
    public:
        static I Copy(const I & value)
        {
            return value;
        }
    };

    template<class I>
    class NdbCopyHelper<I, typename std::enable_if<std::is_base_of<IDbObject, I>::value && !std::is_base_of<NdbObject, I>::value>::type>
    {
    public:
        static I Copy(const I & value)
        {
            OwnerPtr<IDbObject> opObject = NdbObjectCopyUtils::CopyObject(&value);
            return *((I*)(opObject.get()));
        }
    };

    template<class I>
    class NdbCopyHelper<I, typename std::enable_if<std::is_base_of<NdbObject, I>::value>::type>
    {
    public:
        static I Copy(const I & value)
        {
            OwnerPtr<NdbObject> opObject = NdbObjectCopyUtils::CopyObject((const NdbObject*)&value);
            return *((I*)(opObject.get()));
        }
    };

    template<class I>
    class NdbCopyHelper<OwnerPtr<I>, typename std::enable_if<
        property_is_object_cloneable_owner_ptr_type<OwnerPtr<I>>::value ||
        property_is_object_schematic_owner_ptr_type<OwnerPtr<I>>::value
    >::type>
    {
    public:
        static OwnerPtr<I> Copy(const OwnerPtr<I> & value)
        {
            if (nullptr == value.get())
            {
                return nullptr;
            }
            OwnerPtr<NdbObject> opObject = NdbObjectCopyUtils::CopyObject((const NdbObject*)value.get());
            return TransferOwnershipCast<I>(opObject);
        }
    };

    template<class I>
    class NdbCopyHelper<OwnerPtr<I>, typename std::enable_if<
        property_is_idbobject_owner_ptr_type<OwnerPtr<I>>::value &&
        !property_is_object_schematic_owner_ptr_type<gcmp::OwnerPtr<I>>::value
    >::type>
    {
    public:
        static OwnerPtr<I> Copy(const OwnerPtr<I>& value)
        {
            if (nullptr == value.get())
            {
                return nullptr;
            }

            if (const NdbObject* pObj = thread_safe_quick_cast<NdbObject>(value.get()))
            {
                OwnerPtr<NdbObject> opObject = NdbObjectCopyUtils::CopyObject(pObj);
                return TransferOwnershipCast<I>(opObject);
            }
            else
            {
                if (ICloneBehavior* pCloneBehavior = value->GetCloneBehavior())
                {
                    return TransferOwnershipCast<I>(pCloneBehavior->CloneObject());
                }
                return nullptr;
            }
        }
    };

    template<class I>
    class NdbCopyHelper<OwnerPtr<I>, typename std::enable_if<
        !property_is_object_cloneable_owner_ptr_type<OwnerPtr<I>>::value &&
        !property_is_object_schematic_owner_ptr_type<OwnerPtr<I>>::value &&
        !property_is_idbobject_owner_ptr_type<OwnerPtr<I>>::value
    >::type>
    {
    public:
        static OwnerPtr<I> Copy(const OwnerPtr<I> & value)
        {
            return NEW_AS_OWNER_PTR(I, *value);
        }
    };
}



